using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace WindowsGame4
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        public SpriteBatch spriteBatch;
        public MouseState mouseState;
        public List<Movable> movable;
        public Texture2D[] movableTexture;
        public SpriteManager[] movableSM;
        public readonly static string[] movableTexturePath = new string[]
        {
            "car2h",
            "car3h",
            "car2v",
            "car3v"
        };
        public Field field = new Field(10, 10);
        
        SpriteManager terrain;
        SpriteManager fence;
        private int i, j;
        private bool kunci = false;
        private Random rand;
    
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 600;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            field.printField();

            Random random = new Random();

            /*for (int a = 0; a < 5; a++)
            {
                int X = random.Next(0, 6);
                int Y = random.Next(0, 6);
                Movable movObj = new Movable(3, 2);
                if (field.isPlaceable(movObj, X, Y))
                {
                    Console.WriteLine("Objek " + a + ", (" + X + "," + Y + ") is placeable.");
                }
                else
                {
                    Console.WriteLine("Objek " + a + ", (" + X + "," + Y + ") is unplaceable.");
                }
            }*/
            
            IsMouseVisible = true;
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        /// 

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            terrain = new SpriteManager(Content.Load<Texture2D>("terrain"), 2, 2);
            fence = new SpriteManager(Content.Load<Texture2D>("fence"), 2, 3);
            
            // TODO: use this.Content to load your game content here
            movableTexture = new Texture2D[4];
            movableSM = new SpriteManager[10];
            for (int i = 0; i < 4; i++)
            {
                movableTexture[i] = Content.Load<Texture2D>(movableTexturePath[i]);
                movableSM[i] = new SpriteManager(movableTexture[i], 1, 1);
            }
            rand = new Random();
            /*
            movable = new Movable[10];
            movable[0] = new Movable(this, 1, new Vector2(200, 0), movableSM[1]);
            movable[1] = new Movable(this, 0, new Vector2(300, 0), movableSM[0]);
            movable[2] = new Movable(this, 1, new Vector2(500, 0), movableSM[1]);
            movable[3] = new Movable(this, 1, new Vector2(400, 100), movableSM[1]);
            movable[4] = new Movable(this, 0, new Vector2(200, 200), movableSM[0]);
            movable[5] = new Movable(this, 1, new Vector2(500, 200), movableSM[1]);
            movable[6] = new Movable(this, 0, new Vector2(200, 300), movableSM[0]);
            movable[7] = new Movable(this, 0, new Vector2(0, 400), movableSM[2]);
            movable[8] = new Movable(this, 1, new Vector2(300, 400), movableSM[1]);
            movable[9] = new Movable(this, 0, new Vector2(400, 400), movableSM[0]);
            for (int i = 0; i < 10; i++)
            {
                Components.Add(movable[i]);
            }
            */
            movable = new List<Movable>();
            Movable mov = new Movable(this,0,new Vector2(0,100),movableSM[0],2);
            movable.Add(mov);
            Components.Add(mov);
            int baris = 0,kolom = 4;
            while (baris < 6)
            {
                //if (rand.Next(0, 2) == 0)
                //{
                    if (rand.Next(0, 2) == 0 && baris != 1)
                    {
                        int x = rand.Next(0, 2);
                        Movable mov1 = new Movable(this, 0, new Vector2(kolom * 100, baris * 100), movableSM[x],1);
                        movable.Add(mov1);
                        if (mov1.isCollision() || mov1.outofmap())
                        {
                            movable.Remove(mov1);
                        }
                        else
                        {
                            Components.Add(mov1);
                        }
                    }
                    else
                    {
                        int x = rand.Next(2, 4);
                        Movable mov1 = new Movable(this, 1, new Vector2(kolom * 100, baris * 100), movableSM[x],1);
                        movable.Add(mov1);
                        if (mov1.isCollision() || mov1.outofmap())
                        {
                            movable.Remove(mov1);
                        }
                        else
                        {
                            Components.Add(mov1);
                        }
                    }
                //}
                kolom--;
                if (kolom == 0)
                {
                    kolom=4; baris++;
                }
            }

            float ScaleByWidth = (float)GraphicsDevice.PresentationParameters.BackBufferHeight / (float)((terrain.GetTexture().Width / terrain.GetMaxFrameH()) * (field.GetMaxCol() + 2));
            float ScaleByHeight = (float)GraphicsDevice.PresentationParameters.BackBufferHeight / (float)((terrain.GetTexture().Height / terrain.GetMaxFrameV()) * (field.GetMaxRow() + 2));

            if (field.GetMaxCol() > field.GetMaxRow())
            {
                terrain.Scale = ScaleByWidth;
                fence.Scale = ScaleByWidth;
            }
            else
            {
                terrain.Scale = ScaleByHeight;
                fence.Scale = ScaleByHeight;
            }
            
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            if (field.GetGrid()[1, 4] == 2) 
            {
                Exit();
            }
            playinput();
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            int i, j;
            for (i = 0; i < field.GetMaxCol()+2; i++)
            {
                for (j = 0; j < field.GetMaxRow()+2; j++)
                {
                    terrain.Position = new Vector2(i * (float)(terrain.GetTexture().Width / terrain.GetMaxFrameH() * terrain.Scale), j * (float)(terrain.GetTexture().Height / terrain.GetMaxFrameV() * terrain.Scale));
                    if ((i + j) % 2 == 0)
                    {
                        terrain.Draw(this.spriteBatch, 0, 0);
                    }
                    else
                    {
                        terrain.Draw(this.spriteBatch, 1, 0);
                    }

                    fence.Position = new Vector2(i * (float)(fence.GetTexture().Width / fence.GetMaxFrameH() * fence.Scale), j * (float)(fence.GetTexture().Height / fence.GetMaxFrameV() * fence.Scale));
                    if (i == 0)
                    {
                        if (j == 0)
                        {
                            fence.Draw(this.spriteBatch, 0, 1);
                        }
                        else if (j == field.GetMaxRow() + 1)
                        {
                            fence.Draw(this.spriteBatch, 0, 2);
                        }
                        else
                        {
                            fence.Draw(this.spriteBatch, 0, 0);
                        }
                    }
                    else if (i == field.GetMaxCol() + 1)
                    {
                        if (j == 0)
                        {
                            fence.Draw(this.spriteBatch, 1, 1);
                        }
                        else if (j == field.GetMaxRow() + 1)
                        {
                            fence.Draw(this.spriteBatch, 1, 2);
                        }
                        else
                        {
                            fence.Draw(this.spriteBatch, 0, 0);
                        }
                    }
                    else if ((j == 0) || (j == field.GetMaxRow() + 1))
                    {
                        fence.Draw(this.spriteBatch, 1, 0);
                    }
                }
            }
            base.Draw(gameTime);
            spriteBatch.End();
        }

        private void playinput()
        {
            mouseState = Mouse.GetState();
            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                float x = mouseState.X;
                float y = mouseState.Y;
                for (i = 0; i < movable.Count; i++)
                {
                    if (movable[i].isClick(x, y) && !kunci)
                    {
                        j = i;
                        kunci = true;
                    }
                }
                movable[j].moveTo(x, y);
            }
            if (mouseState.LeftButton == ButtonState.Released)
            {
                movable[j].resetmoveto();
                kunci = false;
            }
        }
    }
}
